home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
039a
/
d3d.zip
/
HLPFUN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-08-30
|
27KB
|
938 lines
/* HLPFUN: A function for hidden- line */
/* elimination, using device-independent pixels. */
/* This version includes a providion for curved surfaces */
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <alloc.h>
#include <conio.h>
#include <string.h>
#include <process.h>
#include "grpack.h"
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define max3(x,y,z) ((x)>(y)?max(x,z):max(y,z))
#define min3(x,y,z) ((x)<(y)?min(x,z):min(y,z))
#define xwhole(x) ((int)(((x)-xmin)/deltaX))
#define ywhole(y) ((int)(((y)-ymin)/deltaY))
#define xreal(i) (xmin+((i))*deltaX)
#define M -1000000.0
#define NSCREEN 15
#define BIG 1.e30
int abs(int i);
static void
check_kbhit(void),
add_linesegment(int P, int Q),
viewing(double x, double y, double z,
double *pxe, double *pye, double *pze),
linesegment(double xP, double yP, double zP,
double xQ, double yQ, double zQ, int k);
void
ermes(char *str),
coeff(float rho, float theta, float phi),
init_viewport(void);
static int
counter_clock(int i0, int i1, int i2, int code),
includesvertex(int h, int i, int j),
sameside(double xj, double yj, double xl, double yl,
double xh, double yh, double xi, double yi),
allocsize(int divfactor, int elsize);
extern int nmax, nface, **pface;
extern float xO, yO, zO, xmin, xmax, ymin, ymax;
static int ipixmin, ipixmax, ipixleft, ipixright,
ipix, jpix, jtop, jbot, j_old, jI, topcode[3], *POLY,
npolyalloc, *vertexconvex, ntrsetalloc, npoly,
isize=sizeof(int), LOWER[NSCREEN], UPPER[NSCREEN],
LOW[NSCREEN], UP[NSCREEN], ntrset, maxvertex, jface,
nTRIANGLE, nTRLIST, iTRIANGLE, iTRLIST, inode, itria,
*trset;
extern double v11, v12, v13, v21, v22, v23, v31, v32, v33, v43,
PIdiv180;
static double d, c1, c2,
eps = 1e-5, meps = -1e-5, oneplus=1.+1.e-5,
Xrange, Yrange, Xvp_range, Yvp_range,
deltaX, deltaY, denom, slope,
Xleft[3], Xright[3], Yleft[3], Yright[3],
a, b, c, surfl;
struct linsegface {
int i;
double a, b, c;
struct linsegface *next;
} *lsegfacenode(void);
struct vertex {
int inuse;
float xw, yw, zw;
double xe, ye, ze;
struct linsegface *connect;
} *VERTEX, *pvertex;
extern struct vertex *p;
static struct triangle {
int A, B, C;
double a, b, c, h;
} *TRIANGLE, *ptriangle;
static struct lseglist {
double xP, yP, zP, xQ, yQ, zQ;
int k;
struct lseglist *next;
} *lsegstart, *auxlseg, *lsegnode(void);
struct trlist {
unsigned int ptria;
unsigned int next;
} *TRLIST, *pnode;
struct {
int tr_cov;
float tr_dist;
unsigned int start;
} SCREEN[NSCREEN][NSCREEN], *pointer;
void hlpfun(float rho, float theta, float phi, float surflimit)
{
int P, Q, ii, vertexnr, i, kk, i0, i1, i2, code, count,
polygonconvex, loopcount, jtr, j, n, k;
struct linsegface *ptr, *dummy, *dummy0;
double
Xvp_min=0, Xvp_max, Yvp_min=0, Yvp_max,
fx, fy, Xcenter, Ycenter, Xvp_center, Yvp_center,
xP, yP, zP, xQ, yQ, zQ, XP, YP, XQ, YQ,
Xlft, Xrght, Ylft, Yrght,
xxP, yyP, zzP, xxQ, yyQ, zzQ;
textXY(40, 40, "Please wait ...");
Xvp_max = x_max;
Yvp_max = y_max;
surfl = surflimit;
npolyalloc = 200;
POLY = (int *)farcalloc((long)npolyalloc, (long)isize);
vertexconvex = (int *)farcalloc((long)npolyalloc, (long)isize);
if(POLY == NULL || vertexconvex == NULL) {
ermes("Memory: polygon");
}
VERTEX = p;
/* Now VERTEX points to the same memory area as p does
in module D3D */
/* Initialize screen matrix */
for(ipix=0; ipix<NSCREEN; ipix++)
for(jpix=0; jpix<NSCREEN; jpix++) {
pointer = &(SCREEN[ipix][jpix]);
pointer->tr_cov = -1;
pointer->tr_dist = BIG;
pointer->start = -1;
}
coeff(rho, theta, phi);
maxvertex = nmax - 1; /*nmax is defined in module D3D */
dummy = lsegfacenode();
for(i=1; i<=maxvertex; i++)
VERTEX[i].connect = (VERTEX[i].inuse ? NULL : dummy);
/* dummy indicates: not in use */
/* NULL indicates: empty list (but in use) */
/* Compute screen constants */
Xrange = xmax - xmin;
Yrange = ymax - ymin;
Xvp_range = Xvp_max - Xvp_min;
Yvp_range = Yvp_max - Yvp_min;
fx = Xvp_range/Xrange;
fy = Yvp_range/Yrange;
d = (fx<fy ? fx : fy);
Xcenter = 0.5*(xmin + xmax);
Ycenter = 0.5*(ymin + ymax);
Xvp_center = 0.5*(Xvp_min + Xvp_max);
Yvp_center = 0.5*(Yvp_min + Yvp_max);
c1 = Xvp_center - d*Xcenter;
c2 = Yvp_center - d*Ycenter;
deltaX = oneplus*Xrange/NSCREEN;
deltaY = oneplus*Yrange/NSCREEN;
/* Now we have: Xrange/deltaX < NSCREEN */
iTRLIST = 0;
iTRIANGLE = 0;
nTRLIST = allocsize(4, sizeof(struct trlist));
TRLIST = (struct trlist *)farcalloc((long)nTRLIST,
(long)sizeof(struct trlist));
nTRIANGLE = allocsize(3, sizeof(struct triangle));
TRIANGLE = (struct triangle *)farcalloc((long)nTRIANGLE,
(long)sizeof(struct triangle));
if(TRLIST == NULL || TRIANGLE == NULL)
ermes("Memory: triangles");
for(j=0; j<nface; j++) {
if(pface[j] == NULL)
continue;
n = pface[j][0];
if(n < 0)
ermes("Internal error: n < 0");
if(n == 1)
ermes("Polygon with only one vertex");
POLY[0] = pface[j][1];
npoly = 1;
for(k=2; k<=n; k++) {
i = pface[j][k];
if(npoly == npolyalloc) {
npolyalloc += (npolyalloc>>2);
POLY = (int *)farrealloc(POLY,(long)npolyalloc*isize);
vertexconvex = (int *)
farrealloc(vertexconvex,(long)npolyalloc*isize);
if(POLY == NULL || vertexconvex == NULL)
ermes("Memory: polygons");
}
POLY[npoly++] = i;
}
if(npoly == 1)
ermes("Internal error: npoly = 1");
if(npoly == 2) {
add_linesegment(POLY[0], POLY[1]);
continue;
}
jface = j;
if(!counter_clock(0, 1, 2, 0))
continue; /* backface */
for(i=1; i<=npoly; i++) {
ii = i%npoly;
code = POLY[ii];
vertexnr = abs(code);
if(code<0)
POLY[ii] = vertexnr;
else
add_linesegment(POLY[i-1], vertexnr);
}
/* Triangulation of a polygon */
count = 1;
polygonconvex = 0;
i1 = -1;
while(npoly > 2) {
if(!polygonconvex) {
polygonconvex = 1;
for(ii=0; ii<npoly; ii++) {
i0 = (ii == 0 ? npoly-1 : ii-1);
i2 = (ii == npoly-1 ? 0 : ii+1);
vertexconvex[ii] = counter_clock(i0, ii, i2, 0);
if(!vertexconvex[ii])
polygonconvex = 0;
}
}
loopcount = npoly;
do {
if(++i1 >=npoly)
i1 = 0;
i0 = (i1 == 0 ? npoly-1 : i1 - 1);
i2 = (i1 == npoly-1 ? 0 : i1 + 1);
}
while(--loopcount && !polygonconvex &&
(!vertexconvex[i1] || includesvertex(i0, i1, i2)));
/* store traingle: */
counter_clock(i0, i1, i2, count++);
npoly--;
for(ii=i1; ii<npoly; ii++)
POLY[ii] = POLY[ii+1];
}
}
/* Add nearest triangles to screen lists: */
for(ipix=0; ipix<NSCREEN; ipix++)
for(jpix=0; jpix<NSCREEN; jpix++) {
pointer = &(SCREEN[ipix][jpix]);
if(pointer->tr_cov >= 0) {
pnode = TRLIST + iTRLIST;
pnode->ptria = pointer->tr_cov;
pnode->next = pointer->start;
pointer->start = iTRLIST;
if(++iTRLIST == nTRLIST)
ermes("Memory: Triangle list");
}
}
farfree(POLY);
farfree(vertexconvex);
ntrsetalloc = 1000;
trset = (int *)farcalloc(ntrsetalloc, sizeof(unsigned int));
if(trset == NULL)
ermes("Memory: set of traingles");
lsegstart = NULL;
clearpage();
init_viewport();
/* Draw all line segments as far as they are visible */
for(P=1; P<=maxvertex; P++) {
pvertex = VERTEX + P; /* = &VERTEX[P] */
ptr = pvertex->connect;
if(ptr == dummy || ptr == NULL)
continue;
xP = pvertex->xe;
yP = pvertex->ye;
zP = pvertex->ze;
XP = xP/zP;
YP = yP/zP;
for( ; ptr != NULL; ptr = ptr->next) {
Q = ptr->i;
pvertex = VERTEX + Q; /* = &VERTEX[Q] */
xQ = pvertex->xe;
yQ = pvertex->ye;
zQ = pvertex->ze;
XQ = xQ/zQ;
YQ = yQ/zQ;
/* Using the screen lists, we shall build the
set of triangles that may hide points of PQ: */
if(XP<XQ || (XP == XQ && YP < YQ)) {
Xlft = XP;
Ylft = YP;
Xrght = XQ;
Yrght = YQ;
}
else {
Xlft = XQ;
Ylft = YQ;
Xrght = XP;
Yrght = YP;
}
ipixleft = xwhole(Xlft);
ipixright = xwhole(Xrght);
denom = Xrght - Xlft;
if(ipixleft != ipixright)
slope = (Yrght - Ylft)/denom;
jbot = jtop = ywhole(Ylft);
for(ipix=ipixleft; ipix<=ipixright; ipix++) {
if(ipix == ipixright)
jI = ywhole(Yrght);
else
jI = ywhole(Ylft+(xreal(ipix-1)-Xlft)*slope);
LOWER[ipix] = min(jbot, jI);
jbot = jI;
UPPER[ipix] = max(jtop, jI);
jtop = jI;
}
ntrset = 0;
for(ipix=ipixleft; ipix<=ipixright; ipix++)
for(jpix=LOWER[ipix]; jpix<=UPPER[ipix]; jpix++) {
pointer = &(SCREEN[ipix][jpix]);
inode = pointer->start;
while(inode >= 0) {
/* At the end of the list we have inode = -1 */
pnode = TRLIST + inode;
itria = pnode->ptria;
/* The triangle will be stored only if it is not
yet present in the array trset (the traingle set). */
if(ntrset == ntrsetalloc) {
ntrsetalloc += (ntrsetalloc >> 2);
trset = (int *)farrealloc(trset,
(long)ntrsetalloc*sizeof(unsigned int));
if(trset == NULL)
ermes("Memory: traingle set");
}
trset[ntrset] = itria; /* sentinel */
jtr = 0;
while(trset[jtr] != itria)
jtr++;
if(jtr == ntrset) {
ntrset++; /* store triangle */
}
inode = pnode->next;
}
}
/* Now trset[0], ..., trset[ntrset-1] is the set of
traingles that may hide points of PQ. */
linesegment(xP, yP, zP, xQ, yQ, zQ, 0);
while(lsegstart != NULL) {
xxP = lsegstart->xP;
yyP = lsegstart->yP;
zzP = lsegstart->zP;
xxQ = lsegstart->xQ;
yyQ = lsegstart->yQ;
zzQ = lsegstart->zQ;
kk = lsegstart->k;
auxlseg = lsegstart;
lsegstart = lsegstart->next;
farfree(auxlseg);
linesegment(xxP, yyP, zzP, xxQ, yyQ, zzQ, kk);
}
}
}
farfree(dummy);
farfree(trset);
for(i=1; i<=maxvertex; i++)
if(VERTEX[i].inuse) {
dummy = VERTEX[i].connect;
while(dummy != NULL) {
dummy0 = dummy;
dummy = dummy->next;
farfree(dummy0);
}
}
farfree(TRLIST);
farfree(TRIANGLE);
}
void coeff(float rho, float theta, float phi)
{
double th, ph, costh, sinth, cosph, sinph;
/* Angles in radians: */
th = theta * PIdiv180;
ph = phi * PIdiv180;
costh = cos(th);
sinth = sin(th);
cosph = cos(ph);
sinph = sin(ph);
/* Elements of viewing matrix V: */
v11 = -sinth; v12 = -cosph*costh; v13 = -sinph*costh;
v21 = costh; v22 = -cosph*sinth; v23 = -sinph*sinth;
v31 = 0 ; v32 = sinph; v33 = -cosph;
v43 = rho;
}
static void add_linesegment(int P, int Q)
/* This function may insert line segment PQ in the linked
list starting in VERTEX[p].connect. (If necessary, we
first exchange the values of P and Q such that P becomes
the smaller of the two.) If PQ has been stored in the
list previously, it is not duplicated. If a previously
stored segment PQ is found, we compare the face to which
it belongs with the face to which the new one belongs.
If the normal vectors to these two faces are almost
parallel (the inner product between their normal vectors
being greater than 'surflimit'), the old line segment is
deleted.
*/
{
struct linsegface *ptr, *new, **pp, **pp0;
int iaux;
if(P > Q) {
iaux = P;
P = Q;
Q = iaux;
}
/* Now: P < Q */
pp0 = pp = &(VERTEX[P].connect);
ptr = *pp;
while(ptr != NULL && ptr->i != Q) {
pp = &(ptr->next);
ptr = *pp;
}
if(ptr == NULL) {
new = lsegfacenode();
new->i = Q;
new->a = a;
new->b = b;
new->c = c;
new->next = *pp0;
*pp0 = new;
}
else if (a*(ptr->a) + b*(ptr->b) + c*(ptr->c) > surfl) {
*pp = ptr->next;
farfree(ptr);
}
}
static int counter_clock(int i0, int i1, int i2, int code)
/* code = 0: compute orientation;
code = 1: compute a, b, c, h; store the first triangle;
code > 1: check if next triangle is coplanar; store it
*/
{
int A=POLY[i0], B=POLY[i1], C=POLY[i2], i, l;
double xA, yA, zA, xB, yB, zB, xC, yC, zC, r,
XA, YA, XB, YB, XC, YC, h0,
DA, DB, DC, D, DAB, DAC, DBC, aux, dist,
xR, yR, dev, tot;
static double h;
if(A < 0) A = -A;
if(B < 0) B = -B;
if(A < 0) C = -C;
pvertex = VERTEX + A;
xA = pvertex->xe;
yA = pvertex->ye;
zA = pvertex->ze;
pvertex = VERTEX + B;
xB = pvertex->xe;
yB = pvertex->ye;
zB = pvertex->ze;
pvertex = VERTEX + C;
xC = pvertex->xe;
yC = pvertex->ye;
zC = pvertex->ze;
h0 = xA * (yB*zC - yC*zB) -
xB * (yA*zC - yC*zA) +
xC * (yA*zB - yB*zA);
if(code == 0) {
if(h0 <= eps)
return 0;
a = yA*(zB-zC) - yB*(zA-zC) + yC*(zA-zB) ;
b = -(xA*(zB-zC) - xB*(zA-zC) + xC*(zA-zB));
c = xA*(yB-yC) - xB*(yA-yC) + xC*(yA-yB);
r = sqrt(a*a + b*b + c*c);
if(r == 0.0)
r = eps;
a /= r;
b /= r;
c /= r;
h = h0/r;
return 1;
}
/* If h0=0, plane ABC passes through E and hides nothing.
If h0<0, triangle ABC is a backface.
In both cases, iTRIANGLE is not incremented and the
traingles of the polygon are not stored.
a, b, c will be used in add_linesegment.
*/
dev = fabs(a*xC + b*yC + c*zC - h);
tot = eps + 0.001*fabs(h);
if(dev > tot) {
to_text();
printf("Vertices not in the same plane:\n");
for(i=1; i<pface[jface][0]; i++)
printf("%d ", pface[jface][i]);
exit(1);
}
ptriangle = TRIANGLE + iTRIANGLE;
ptriangle->A = A;
ptriangle->B = B;
ptriangle->C = C;
ptriangle->a = a;
ptriangle->b = b;
ptriangle->c = c;
ptriangle->h = h;
/* The triangle will be now be stored in the screen lists
of the associated pixels; first the array LOWER,
UPPER, LOW, UP are defined:
*/
XA = xA/zA;
YA = yA/zA;
XB = xB/zB;
YB = yB/zB;
XC = xC/zC;
YC = yC/zC;
DA = XB*YC - XC*YB;
DB = XC*YA - XA*YC;
DC = XA*YB - XB*YA;
D = DA + DB + DC;
DAB= DC - M*(XA-XB);
DAC= DB - M*(XC-XA);
DBC= DA - M*(XB-XC);
topcode[0] = (D*DAB>0);
topcode[1] = (D*DAC>0);
topcode[2] = (D*DBC>0);
Xleft[0] = XA; Yleft[0] = YA; Xright[0] = XB; Yright[0] = YB;
Xleft[1] = XA; Yleft[1] = YA; Xright[1] = XC; Yright[1] = YC;
Xleft[2] = XB; Yleft[2] = YB; Xright[2] = XC; Yright[2] = YC;
for(l=0; l<3; l++) /* l = triangle - side number */
if(Xleft[l] > Xright[l] ||
(Xleft[l] == Xright[l] && Yleft[l] > Yright[l])) {
aux = Xleft[l]; Xleft[l] = Xright[l]; Xright[l] = aux;
aux = Yleft[l]; Yleft[l] = Yright[l]; Yright[l] = aux;
}
ipixmin = xwhole(min3(XA,XB,XC));
ipixmax = xwhole(max3(XA,XB,XC));
for(ipix=ipixmin; ipix<=ipixmax; ipix++) {
LOWER[ipix] = UP[ipix] = 10000;
UPPER[ipix] = LOW[ipix] = -10000;
}
for(l=0; l<3; l++) {
ipixleft = xwhole(Xleft[l]);
ipixright = xwhole(Xright[l]);
denom = Xright[l] - Xleft[l];
if(ipixleft != ipixright)
slope = (Yright[l] - Yleft[l])/denom;
j_old = ywhole(Yleft[l]);
for(ipix=ipixleft; ipix<=ipixright; ipix++) {
if(ipix == ipixright)
jI = ywhole(Yright[l]);
else
jI = ywhole(Yleft[l] + (xreal(ipix+1) - Xleft[l])*slope);
if(topcode[l]) {
UPPER[ipix] = max3(j_old, jI, UPPER[ipix]);
UP[ipix] = min3(j_old, jI, UP[ipix]);
}
else {
LOWER[ipix] = min3(j_old, jI, LOWER[ipix]);
LOW[ipix] = max3(j_old, jI, LOW[ipix]);
}j_old = jI;
}
}
/* For screen column ipix, the triangle is associated
only with pixels in the rows
LOWER[ipix], ..., UPPER[ipix].
The subrange LOW[ipix]+1,...,UP[ipix]-1 of these rows
denote pixels that lie completely within the triangle.
*/
for(ipix=ipixmin; ipix<=ipixmax; ipix++)
for(jpix=LOWER[ipix]; jpix<=UPPER[ipix]; jpix++) {
pointer = &(SCREEN[ipix][jpix]);
if(jpix>LOW[ipix] && jpix<UP[ipix]) {
xR = xmin + (ipix + 0.5)*deltaX;
yR = ymin + (jpix + 0.5)*deltaY;
denom = a*xR + b*yR + c*d;
dist = fabs(denom)>eps ? h*sqrt(xR*xR + yR*yR + 1.)/denom : BIG;
/* The line drawn from the viewpoint E to pixel point (xR, yR, 1)
intersects plane ABC at a distance dist from E.
*/
if(dist < pointer->tr_dist) {
pointer->tr_cov = iTRIANGLE;
pointer->tr_dist = dist;
}
}
else { /* Add triangle to screen list: */
pnode = TRLIST + iTRLIST;
pnode->ptria = iTRIANGLE;
pnode->next = pointer->start;
pointer->start = iTRLIST;
if(++iTRLIST == nTRLIST)
ermes("Memory: Triangle list");
}
}
if(++iTRIANGLE == nTRIANGLE)
ermes("Memory: Triangles");
return 1;
}
static void viewing(double x, double y, double z,
double *pxe, double *pye, double *pze)
{
*pxe = v11*x + v21*y;
*pye = v12*x + v22*y + v32*z;
*pze = v13*x + v23*y + v33*z + v43;
}
static void linesegment(double xP, double yP, double zP,
double xQ, double yQ, double zQ, int k)
/* Line segment PQ is to be drawn, as far as it is not
hidden by triangles trset[k] to trset[ntrset-1]. */
{
int A, B, C, i, Pbeyond, Qbeyond,
outside, Poutside, Qoutside, eA, eB, eC, sum;
double a, b, c, h, hP, hQ, r1, r2, r3,
xA, yA, zA, xB, yB, zB, xC, yC, zC,
dA, dB, dC, labmin, labmax, lab, mu,
xmin, ymin, zmin, xmax, ymax, zmax,
C1, C2, C3, K1, K2, K3, denom1, denom2,
Cpos, Ppos, Qpos, aux, eps1;
struct triangle *ptriangle;
while(k<ntrset) {
itria = trset[k];
ptriangle = TRIANGLE + itria;
a = ptriangle->a;
b = ptriangle->b;
c = ptriangle->c;
h = ptriangle->h;
/* Test 1: */
hP = a*xP + b*yP + c*zP;
hQ = a*xQ + b*yQ + c*zQ;
eps1 = eps + eps*h;
if(hP-h <= eps1 && hQ-h <= eps1) {
k++;
continue; /* PQ not behind ABC */
}
/* Test 2: */
K1 = yP*zQ - yQ*zP;
K2 = zP*xQ - zQ*xP;
K3 = xP*yQ - xQ*yP;
A = ptriangle->A;
B = ptriangle->B;
C = ptriangle->C;
pvertex = VERTEX + A;
xA = pvertex->xe;
yA = pvertex->ye;
zA = pvertex->ze;
pvertex = VERTEX + B;
xB = pvertex->xe;
yB = pvertex->ye;
zB = pvertex->ze;
pvertex = VERTEX + C;
xC = pvertex->xe;
yC = pvertex->ye;
zC = pvertex->ze;
dA = K1*xA + K2*yA + K3*zA;
dB = K1*xB + K2*yB + K3*zB;
dC = K1*xC + K2*yC + K3*zC;
/* If dA, dB and dC have the same sign, the vertices
A, B, C lie at the same side of plane EPQ. */
eA = dA>eps ? 1 : dA < meps ? -1 : 0;
eB = dB>eps ? 1 : dB < meps ? -1 : 0;
eC = dC>eps ? 1 : dC < meps ? -1 : 0;
sum = eA + eB + eC;
if(abs(sum) >= 2) {
k++;
continue;
}
/* If this test succeeds, the (infinite) line PQ
lies outside the pyramid EABC (or the line and the
pyramid have at most one point in common.
If the test fails, there is a point if intersection */
/* Test 3: */
Poutside = Qoutside = 0;
labmin = 1.;
labmax = 0.;
for(i=0; i<3; i++) {
C1 = yA*zB - yB*zA;
C2 = zA*xB - zB*xA;
C3 = xA*yB - xB*yA;
/* C1 x + C2 y + C3 z = 0 is plane EAB */
Cpos = C1*xC + C2*yC + C3*zC;
Ppos = C1*xP + C2*yP + C3*zP;
Qpos = C1*xQ + C2*yQ + C3*zQ;
denom1 = Qpos - Ppos;
if(Cpos > eps) {
Pbeyond = Ppos<meps;
Qbeyond = Qpos<meps;
outside = Pbeyond && Qpos<=eps || Qbeyond && Ppos<=eps;
}
else if(Cpos<meps) {
Pbeyond = Ppos>eps;
Qbeyond = Qpos>eps;
outside = Pbeyond && Qpos>=meps || Qbeyond && Ppos>=meps;
}
else
outside = 1;
if(outside)
break;
lab = fabs(denom1) <= eps ? 1.e7 : -Ppos/denom1;
/* lab indicates where PQ meet plane EAB */
Poutside |= Pbeyond;
Qoutside |= Qbeyond;
denom2 = dB - dA;
mu = fabs(denom2) <= eps ? 1.e7 : -dA/denom2;
/* mu tells where AB meets plane EPQ */
if(mu >= meps && mu <= oneplus && lab >= meps && lab <= oneplus) {
if(lab < labmin)
labmin = lab;
if(lab > labmax)
labmax = lab;
}
aux = xA; xA = xB; xB = xC; xC = aux;
aux = yA; yA = yB; yB = yC; yC = aux;
aux = zA; zA = zB; zB = zC; zC = aux;
aux = dA; dA = dB; dB = dC; dC = aux;
}
if(outside) {
k++;
continue;
}
/* Test 4: */
if(!(Poutside || Qoutside))
return; /* PQ invisible */
/* Test 5: */
r1 = xQ - xP;
r2 = yQ - yP;
r3 = zQ - zP;
xmin = xP + labmin*r1;
ymin = yP + labmin*r2;
zmin = zP + labmin*r3;
if(a*xmin + b*ymin + c*zmin -h < -eps1) {
k++;
continue;
}
xmax = xP + labmax*r1;
ymax = yP + labmax*r2;
zmax = zP + labmax*r3;
if(a*xmax + b*ymax + c*zmax -h < -eps1) {
k++;
continue;
}
/* If this test succeeds, an intersection of PQ
and the pyramid lies in front of plane ABC. */
/* Test 6: */
if(Poutside || hP < h - eps1) {
auxlseg = lsegstart;
lsegstart = lsegnode();
lsegstart->xP = xP;
lsegstart->yP = yP;
lsegstart->zP = zP;
lsegstart->xQ = xmin;
lsegstart->yQ = ymin;
lsegstart->zQ = zmin;
lsegstart->k = k+1;
lsegstart->next = auxlseg;
}
if(Qoutside || hQ < h - eps1) {
auxlseg = lsegstart;
lsegstart = lsegnode();
lsegstart->xP = xmax;
lsegstart->yP = ymax;
lsegstart->zP = zmax;
lsegstart->xQ = xQ;
lsegstart->yQ = yQ;
lsegstart->zQ = zQ;
lsegstart->k = k+1;
lsegstart->next = auxlseg;
}
return;
}
move(d*xP/zP+c1, d*yP/zP+c2);
draw(d*xQ/zQ+c1, d*yQ/zQ+c2);
}
void init_viewport(void)
{
float len = 0.3, len1 = 0.2;
move(0.0, len);
draw(0.0, 0.0);
draw(len, 0.0);
move(x_max-len, 0.0);
draw(x_max, 0.0);
draw(x_max, len);
move(x_max, y_max-len1);
draw(x_max, y_max);
draw(x_max-len1, y_max);
move(len1, y_max);
draw(0.0, y_max);
draw(0.0, y_max-len1);
/* The distinction between len and len1 enables us to
tell the top from the bottom */
}
static int includesvertex(int h, int i, int j)
/* Does triangle hij include another vertex? */
{
int l;
double zh, zi, zj, zl, XH, YH, XI, YI, XJ, YJ, XL, YL;
pvertex = VERTEX + POLY[h]; zh = pvertex->ze;
XH = pvertex->xe / zh; YH = pvertex->ye /zh;
pvertex = VERTEX + POLY[i]; zi = pvertex->ze;
XI = pvertex->xe / zi; YI = pvertex->ye /zi;
pvertex = VERTEX + POLY[j]; zj = pvertex->ze;
XJ = pvertex->xe / zj; YJ = pvertex->ye /zj;
for (l=0; l<npoly; l++) {
if(!vertexconvex[l] && l != h && l != i && l != j) {
pvertex = VERTEX + POLY[l]; zl = pvertex->ze;
XL = pvertex->xe / zl;
YL = pvertex->ye / zl;
if(sameside(XH, YH, XL, YL, XI, YI, XJ, YJ) &&
sameside(XI, YI, XL, YL, XJ, YJ, XH, YH) &&
sameside(XJ, YJ, XL, YL, XH, YH, XI, YI))
return 1;
}
}
return 0;
}
static int sameside(double xj, double yj, double xl, double yl,
double xh, double yh, double xi, double yi)
/* Do points j and l lie on the same side of line hi? */
{
double a, b, c;
a = yh - yi;
b = xi - xh;
c = xh*yi - yh*xi;
return (a*xj + b*yj + c) * (a*xl + b*yl + c) > 0.0;
}
struct lseglist *lsegnode(void)
{
struct lseglist *p;
p = (struct lseglist *)
farmalloc((long)sizeof(struct lseglist));
if(p == NULL)
ermes("Memory: line segment PQ");
return p;
}
struct linsegface *lsegfacenode(void)
{
struct linsegface *p;
p = (struct linsegface *)
farmalloc((long)sizeof(struct linsegface));
if(p == NULL)
ermes("Memory: edges");
return p;
}
static int allocsize(int divfactor, int elsize)
{
long lll;
lll = (farcoreleft()/divfactor)/elsize;
return (lll < 32767 ? (int)lll : 32767);
}